#pragma once

#include "../common/Log.hpp"
#include "../common/SqliteHelper.hpp"
#include "../common/FileHelper.hpp"
#include "../common/message.pb.h"
#include "Exchange.hpp"
#include "ExchangeMapper.hpp"
#include <google/protobuf/map.h>
#include <iostream>
#include <string>
#include <unordered_map>
#include <mutex>
#include <memory>

namespace micromq
{
    class ExchangeManager
    {
    public:
        using ptr = std::shared_ptr<ExchangeManager>;
    public:
        ExchangeManager(const std::string& dbFileName): _mapper(dbFileName)
        {
            _exchanges = _mapper.selectAll();
        }

        bool declareExchange(const std::string& name, ExchangeType type, bool durable, bool autoDelete, 
            const google::protobuf::Map<std::string, std::string>& args)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            if(_exchanges.find(name) != _exchanges.end()) return false; //不调isExists防止锁重入
            auto exchange = std::make_shared<Exchange>(name, type, durable, autoDelete, args);
            if(durable = true) _mapper.insertExchange(exchange);
            _exchanges[name] = exchange;
            return true;
        }

        void removeExchange(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            if(_exchanges.find(name) == _exchanges.end()) return;
            if(_exchanges[name]->_durable == true) _mapper.deleteExchange(name);
            _exchanges.erase(name);
        }

        Exchange::ptr getExchange(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            if(_exchanges.find(name) == _exchanges.end()) return nullptr;
            return _exchanges[name];
        }

        std::unordered_map<std::string, Exchange::ptr> getAllExchange()
        {
            std::unique_lock<std::mutex> lock(_mtx);
            return _exchanges;
        }

        bool isExists(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            return _exchanges.find(name) != _exchanges.end();
        }

        int size()
        {
            return _exchanges.size();
        }

        void clear()
        {
            std::unique_lock<std::mutex> lock(_mtx);
            _mapper.removeTable();
            _exchanges.clear();
        }

        ~ExchangeManager()
        {}
    private:
        ExchangeMapper _mapper;
        std::unordered_map<std::string, Exchange::ptr> _exchanges;
        std::mutex _mtx;
    };
};